package cn.yeziji.forum.utils;

import com.github.benmanes.caffeine.cache.Cache;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;

/**
 * caffeine 缓存工具类
 *
 * @author gzkemays
 * @since 2021/12/23 21:34
 */
public class CaffeineUtils<T> {
  private Cache<String, Object> cache;
  private static final String EXPIRED_PREFIX_KEY = "_CAFFEINE__EXPIRED_";

  public CaffeineUtils(Cache<String, Object> cache) {
    this.cache = cache;
  }

  public T get(String key) {
    return (T) cache.getIfPresent(key);
  }

  public void putHash(String key, String hashKey, Object value) {
    Object ifPresent = cache.getIfPresent(key);
    HashMap<Object, Object> map;
    if (!(ifPresent instanceof HashMap)) {
      map = new HashMap<>();
    } else {
      map = (HashMap<Object, Object>) ifPresent;
    }
    map.put(hashKey, value);
    cache.put(key, map);
  }

  public Object getHash(String key, String hashKey) {
    T t = get(key);
    if (t != null) {
      HashMap<Object, Object> map = (HashMap<Object, Object>) t;
      return map.get(hashKey);
    }
    return null;
  }

  /**
   * 如果无添加
   *
   * <p>如果缓存中没有该值则进行 put 操作，否则返回数据
   *
   * @param key 键值
   * @param value 数据
   * @return 如果有值
   */
  public T putIfNone(String key, T value) {
    return putIfNoneRefreshTo(key, value, false);
  }

  /**
   * 重新刷新 cache
   *
   * @param key 键值
   * @param value 数据
   * @return 数据
   */
  public T putIfNoneRefresh(String key, T value) {
    putIfNoneRefreshTo(key, value, true);
    return value;
  }

  /**
   * 是否包含指定键值
   *
   * @param key 键值
   * @return 键值数据
   */
  public boolean hasKey(String key) {
    /*    if (ifPresent == null && blur) {
      ConcurrentMap<String, Object> soc = cache.asMap();
      if (!soc.isEmpty()) {
        for (Map.Entry<String, Object> soe : soc.entrySet()) {
          String soeKey = soe.getKey();
          if (soeKey.contains(key)) {
            return true;
          }
        }
      }
    }*/
    return cache.getIfPresent(key) != null;
  }

  /**
   * 删除一级缓存
   *
   * @param key 键值
   */
  public void remove(String key) {
    if (hasKey(key)) {
      cache.invalidate(key);
      return;
    }
    // 避免 hashKey 无法直接删除
    ConcurrentMap<String, Object> soc = cache.asMap();
    for (Map.Entry<String, Object> soe : soc.entrySet()) {
      String soeKey = soe.getKey();
      if (soeKey.contains(key)) {
        cache.invalidate(soeKey);
      }
    }
  }

  /**
   * 是否重置替换
   *
   * @param key 键值
   * @param value 数据
   * @param refresh 是否重置
   * @return 返回数据
   */
  private T putIfNoneRefreshTo(String key, T value, boolean refresh) {
    T t = (T) cache.getIfPresent(key);
    if (t == null) {
      cache.put(key, value);
      return null;
    } else if (refresh) {
      cache.put(key, value);
    }
    return t;
  }
}
